using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;

namespace Tool
{
    class HighLevelInterface
    {
        private Editor m_parent;

        public HighLevelInterface(Editor parent)
        {
            m_parent = parent;
        }

        // ***** NEEDED BY HIGH LEVEL *****
        // * SAVING *
        //   - Save a bool with each Event whether it is looping or not
        //   - Save an int with each SubEvent for pitch shifting
        //   - Need to be able to clear EVERYTHING
        //
        // * LOADING *
        //   - Everything (including new additions above)
        //
        // * OTHER *
        //   - Need to be able to get wav data by filename/path
        // ********************************

        public void LoadXMLFile(string filename)
        {
            m_parent.DeleteAllData();
            m_parent.GetToolSystemInterface().Clear();

            unsafe
            {
                m_parent.GetToolSystemInterface().LoadSoundXML((sbyte*)System.Runtime.InteropServices.Marshal.StringToHGlobalAnsi(filename).ToPointer());
                string xmlFileName = ((Editor)m_parent).ParseFilename(filename);
                string xmlFilePath = filename.Remove(filename.Length-xmlFileName.Length);

                    // Load sound files
                uint soundHandle = 0;
                bool firstSound = true;
                do
                {
                    soundHandle = m_parent.GetToolSystemInterface().GetSoundFileHandle(firstSound); firstSound = false;

                    if (soundHandle != 0)
                    {
                        string fname = System.Runtime.InteropServices.Marshal.PtrToStringAnsi((IntPtr)m_parent.GetToolSystemInterface().GetSoundFilename(&soundHandle));
                        string name = System.Runtime.InteropServices.Marshal.PtrToStringAnsi((IntPtr)m_parent.GetToolSystemInterface().GetSoundName(&soundHandle));

                        if (!System.IO.File.Exists(xmlFilePath + fname))
                        {
                            m_parent.m_cantFindWavDlg.label1.Text = "Cannot find and load specified .WAV file.";
                            m_parent.m_cantFindWavDlg.button1.Location = new Point(m_parent.m_cantFindWavDlg.Width / 2 - 
                                m_parent.m_cantFindWavDlg.button1.Width / 2, m_parent.m_cantFindWavDlg.button1.Location.Y);

                            m_parent.m_cantFindWavDlg.ShowDialog();
                            continue;
                        }

                            // Unused by Tool
                        //string path = (System.Runtime.InteropServices.Marshal.PtrToStringAnsi((IntPtr)m_parent.GetToolSystemInterface().GetSoundPath());

                            // Sound added to Sound Library
                        m_parent.m_soundLibrary.AddFile(new SoundFile(xmlFilePath + fname, (Editor)m_parent));
                    }
                } while (soundHandle != 0);

                    // Load Variables
                uint varHandle = 0;
                bool firstVar = true;
                do
                {
                    varHandle = m_parent.GetToolSystemInterface().GetVariableHandle(firstVar); firstVar = false;

                    if (varHandle != 0)
                    {
                        string name = System.Runtime.InteropServices.Marshal.PtrToStringAnsi((IntPtr)m_parent.GetToolSystemInterface().GetVariableName(&varHandle));
                        
                            // Unused by Tool
                        float minValue = m_parent.GetToolSystemInterface().GetVariableMin(&varHandle);
                        float maxValue = m_parent.GetToolSystemInterface().GetVariableMax(&varHandle);

                            // Variable added to Global Variable Manager
                        m_parent.m_globalVarManager.AddGlobalVariable(name);
                    }
                } while (varHandle != 0);

            
                    // Load Events
                uint evntHandle = 0;
                bool firstEvent = true;
                do
                {
                    evntHandle = m_parent.GetToolSystemInterface().GetEventHandle(firstEvent); firstEvent = false;

                    if (evntHandle != 0)
                    {
                        string evntName = System.Runtime.InteropServices.Marshal.PtrToStringAnsi((IntPtr)m_parent.GetToolSystemInterface().GetEventName(&evntHandle));

                        m_parent.AddEventNode(new TreeNode(evntName));
                        m_parent.EventTree.SelectedNode = m_parent.EventTree.Nodes[ m_parent.EventTree.Nodes.Count - 1 ];
                        m_parent.GetEventTree().AddEvent(evntName);

                        bool loop = m_parent.GetToolSystemInterface().GetEventLooping(&evntHandle);
                        m_parent.GetEventTree().GetEvent(evntName).SetLoop(loop);

                            // Load SubEvents (Sounds)
                        uint subEvntHandle = 0;
                        bool firstSubEvent = true;
                        int soundIndex = 0;
                        do
                        {
                            subEvntHandle = m_parent.GetToolSystemInterface().GetSubEventHandle(&evntHandle, firstSubEvent); firstSubEvent = false;

                            if (subEvntHandle != 0)
                            {
                                string subEvntName = System.Runtime.InteropServices.Marshal.PtrToStringAnsi((IntPtr)m_parent.GetToolSystemInterface().GetSoundName(&evntHandle, &subEvntHandle));
                                float subEvntTriggerTime = m_parent.GetToolSystemInterface().GetTriggerTime(&evntHandle, &subEvntHandle);

                                m_parent.GetEventTree().GetEvent(evntName).AddSound(
                                    new EventSound(subEvntName, m_parent.SoundEditorPanel.Width,
                                    m_parent.SoundEditorPanel.Height, m_parent.SoundEditorPanel.Left,
                                    m_parent.SoundEditorPanel.Top, (Editor)m_parent, true)); // This WILL have points

                                float timeOffset = m_parent.GetToolSystemInterface().GetTriggerTime(&evntHandle, &subEvntHandle);
                                m_parent.GetEventTree().GetEventSound(evntName, soundIndex).SetTimeOffset((int)timeOffset);

                                int pitchShift = m_parent.GetToolSystemInterface().GetPitchShift(&evntHandle, &subEvntHandle);
                                m_parent.GetEventTree().GetEventSound(evntName, soundIndex).SetPitchShift(pitchShift);

                                bool streaming = m_parent.GetToolSystemInterface().GetStreaming(&evntHandle, &subEvntHandle);
                                
                                int soundBankIndex = 0;
                                for (int i = 0; i < m_parent.SoundBankGrid.Rows.Count; ++i)
                                {
                                    if (m_parent.SoundBankGrid.Rows[i].Cells[0].Value.ToString() == subEvntName)
                                    {
                                        soundBankIndex = i;
                                        break;
                                    }
                                }
                                
                                if( m_parent.m_soundLibrary.GetFileByFilename(subEvntName) != null )
                                    m_parent.m_soundLibrary.GetFileByFilename(subEvntName).SetStreaming(streaming, soundBankIndex);

                                TreeNode temp = new TreeNode(subEvntName);
                                temp.ContextMenuStrip = m_parent.SoundsRightClickMenu;
                                m_parent.EventTree.SelectedNode.Nodes.Add(temp);
                                m_parent.EventTree.SelectedNode.Expand();
                                m_parent.EventTree.SelectedNode.ContextMenuStrip = m_parent.EventsRightClickMenu;






                                    // Load all of the effects in for each sound
                                uint effectHandle = 0;
                                bool firstEffect = true;
                                do
                                {
                                    effectHandle = m_parent.GetToolSystemInterface().GetEffectHandle(&evntHandle, &subEvntHandle, firstEffect); firstEffect = false;

                                    if (effectHandle != 0)
                                    {

                                        uint effectGraphHandle = m_parent.GetToolSystemInterface().GetEffectGraph(&evntHandle, &subEvntHandle, &effectHandle);

                                        if (effectGraphHandle != 0)
                                        {
                                            uint effectGraphType = m_parent.GetToolSystemInterface().GetEffectType(&evntHandle, &subEvntHandle, &effectHandle);
                                            ArrayList editPoints = new ArrayList();
                                            switch (effectGraphType)
                                            {
                                                case (int)(EDIT_TYPE.EDIT_PAN + 1):
                                                    {
                                                        editPoints = m_parent.GetEventTree().GetEventSound(evntName, soundIndex).GetPanModifier().GetEditPoints();
                                                        break;
                                                    }
                                                case (int)(EDIT_TYPE.EDIT_VOLUME + 1):
                                                    {
                                                        editPoints = m_parent.GetEventTree().GetEventSound(evntName, soundIndex).GetVolumeModifier().GetEditPoints();
                                                        break;
                                                    }
                                                case (int)(EDIT_TYPE.EDIT_DISTORTION + 1):
                                                    {
                                                        editPoints = m_parent.GetEventTree().GetEventSound(evntName, soundIndex).GetDistModifier().GetEditPoints();
                                                        break;
                                                    }
                                                case (int)(EDIT_TYPE.EDIT_REVERB + 1):
                                                    {
                                                        editPoints = m_parent.GetEventTree().GetEventSound(evntName, soundIndex).GetReverbModifier().GetEditPoints();
                                                        break;
                                                    }
                                            }

                                            // Now add all of the graph's points to the correct list
                                            uint graphPointCount = m_parent.GetToolSystemInterface().GetPointCount(&effectGraphHandle);

                                            editPoints.Clear();

                                            for (uint point = 0; point < graphPointCount; ++point)
                                            {
                                                float x = m_parent.GetToolSystemInterface().GetPointX(&effectGraphHandle, point);
                                                float y = m_parent.GetToolSystemInterface().GetPointY(&effectGraphHandle, point);

                                                editPoints.Add(new SoundEditorPoint((int)(x * ((float)m_parent.SoundEditorPanel.Width)),
                                                    (int)(y * ((float)m_parent.SoundEditorPanel.Height)),
                                                    m_parent.SoundEditorPanel.Width,
                                                    m_parent.SoundEditorPanel.Height));
                                            }
                                        }
                                    }
                                } while (effectHandle != 0);





                            }
                            ++soundIndex;
                        } while (subEvntHandle != 0);
                    }
                } while (evntHandle != 0);

            }
            
        }

        public void UpdateXML()
        {
            // ***** Update all the sound files *****

            ArrayList fileList = m_parent.m_soundLibrary.m_FileList;

            for (int file = 0, fileSize = fileList.Count; file < fileSize; ++file)
            {
                string fname = ((SoundFile)fileList[file]).GetFileName();
                string name = fname.Remove(fname.Length - 4);

                unsafe
                {
                    m_parent.GetToolSystemInterface().NewSoundFile((sbyte*)System.Runtime.InteropServices.Marshal.StringToHGlobalAnsi(name).ToPointer(),
                    (sbyte*)System.Runtime.InteropServices.Marshal.StringToHGlobalAnsi(fname).ToPointer());
                }
            }

            // ***** Variables *****

            ArrayList varList = m_parent.m_globalVarManager.GetGlobalVariables();

            for (int var = 0, varSize = varList.Count; var < varSize; ++var)
            {
                string name = ((GlobalVariable)varList[var]).m_name;

                unsafe
                {
                    uint varHandle = m_parent.GetToolSystemInterface().NewVariable(
                        (sbyte*)System.Runtime.InteropServices.Marshal.StringToHGlobalAnsi(name).ToPointer(), 0.0f, 1.0f);
                    m_parent.GetToolSystemInterface().SetVariableValue(&varHandle, ((GlobalVariable)varList[var]).m_value);
                }
            }

            // ***** Events *****

            TreeNodeCollection evntList = m_parent.EventTree.Nodes;

            for (int evnt = 0, evntSize = evntList.Count; evnt < evntSize; ++evnt)
            {
                TreeNodeCollection evntSoundList = evntList[evnt].Nodes;

                if (evntSoundList.Count == 0)
                {
                    continue;
                }

                uint evntHandle = 0;
                unsafe
                {
                    evntHandle = m_parent.GetToolSystemInterface().NewEvent(
                        (sbyte*)System.Runtime.InteropServices.Marshal.StringToHGlobalAnsi(evntList[evnt].Text).ToPointer(),
                        m_parent.GetEventTree().GetEvent(evntList[evnt].Text).GetLoop());
                }

                    // Loop through each sound in the event
                for (int snd = 0, sndSize = evntSoundList.Count; snd < sndSize; ++snd )
                {
                    uint subEventHandle = 0;
                    unsafe
                    {
                        int timeOffset = m_parent.GetEventTree().GetEventSound(evntList[evnt].Text, snd).GetTimeOffset();
                        int pitchShift = m_parent.GetEventTree().GetEventSound(evntList[evnt].Text, snd).GetPitchShift();
                        bool streaming = m_parent.m_soundLibrary.GetFileByFilename(evntSoundList[snd].Text).GetStreaming();

                        subEventHandle = m_parent.GetToolSystemInterface().AddSubEvent(&evntHandle,
                            (sbyte*)System.Runtime.InteropServices.Marshal.StringToHGlobalAnsi(evntSoundList[snd].Text).ToPointer(),
                            timeOffset,
                            pitchShift,
                            streaming );
                    }

                        // Loop through each graph/modifier type for each sound
                    for (int mod = 0, modSize = (int)(EDIT_TYPE.EDIT_TOTAL_ITEMS); mod < modSize; ++mod)
                    {
                            // Graph Naming Convention: Event_SoundName_SoundIndex_#
                        string graphName = evntList[evnt].Text + "_" + (evntSoundList[snd].Text).Remove(evntSoundList[snd].Text.Length-4,4) + "_" + snd + "_" + mod;

                        uint graphHandle = 0;
                        unsafe
                        {
                            graphHandle = m_parent.GetToolSystemInterface().NewGraph(
                                (sbyte*)System.Runtime.InteropServices.Marshal.StringToHGlobalAnsi(graphName).ToPointer());
                        }

                        ArrayList graphPoints = new ArrayList();

                            // We are ASSUMING every modifier has a variable
                        string graphVariableName = "poop";
                        switch (mod)
                        {
                            case (int)(EDIT_TYPE.EDIT_PAN):
                                {
                                    graphPoints = m_parent.GetEventTree().GetEventSound(evntList[evnt].Text, snd).GetPanModifier().GetEditPoints();
                                    graphVariableName = m_parent.GetEventTree().GetEventSound(evntList[evnt].Text, snd).GetVarName(EDIT_TYPE.EDIT_PAN);
                                    break;
                                }
                            case (int)(EDIT_TYPE.EDIT_VOLUME):
                                {
                                    graphPoints = m_parent.GetEventTree().GetEventSound(evntList[evnt].Text, snd).GetVolumeModifier().GetEditPoints();
                                    graphVariableName = m_parent.GetEventTree().GetEventSound(evntList[evnt].Text, snd).GetVarName(EDIT_TYPE.EDIT_VOLUME);
                                    break;
                                }
                            case (int)(EDIT_TYPE.EDIT_DISTORTION):
                                {
                                    graphPoints = m_parent.GetEventTree().GetEventSound(evntList[evnt].Text, snd).GetDistModifier().GetEditPoints();
                                    graphVariableName = m_parent.GetEventTree().GetEventSound(evntList[evnt].Text, snd).GetVarName(EDIT_TYPE.EDIT_DISTORTION);
                                    break;
                                }
                            case (int)(EDIT_TYPE.EDIT_REVERB):
                                {
                                    graphPoints = m_parent.GetEventTree().GetEventSound(evntList[evnt].Text, snd).GetReverbModifier().GetEditPoints();
                                    graphVariableName = m_parent.GetEventTree().GetEventSound(evntList[evnt].Text, snd).GetVarName(EDIT_TYPE.EDIT_REVERB);
                                    break;
                                }
                        }

                            // Now loop through the graph points and add them to the xml graph
                        for (int graphPoint = 0, graphPointSize = graphPoints.Count; graphPoint < graphPointSize;  ++graphPoint)
                        {
                            unsafe
                            {
                                m_parent.GetToolSystemInterface().AddPoint(&graphHandle,
                                    ((SoundEditorPoint)graphPoints[graphPoint]).GetNormalizedX(),
                                    ((SoundEditorPoint)graphPoints[graphPoint]).GetNormalizedY());
                            }
                        }

                            // Set the name of the variable controlling the graph's value
                        unsafe
                        {
                            m_parent.GetToolSystemInterface().AddSoundEffect(&evntHandle, &subEventHandle,
                                (sbyte*)System.Runtime.InteropServices.Marshal.StringToHGlobalAnsi(graphName).ToPointer(),
                                (sbyte*)System.Runtime.InteropServices.Marshal.StringToHGlobalAnsi(graphVariableName).ToPointer(), (uint)(mod+1));
                        }
                    }
                }
            }
        }

        public void SaveXMLFile(string filename)
        {
            m_parent.GetToolSystemInterface().Clear();

            UpdateXML();

            unsafe
            {
                m_parent.GetToolSystemInterface().SaveSoundXML(
                    (sbyte*)System.Runtime.InteropServices.Marshal.StringToHGlobalAnsi(filename).ToPointer());
            }
        }
    }
}
